﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MDF.Cacher.Interfaces;
using System.Threading;
using MDF.Logger.Managements;

namespace MDF.Cacher.Implements
{
    /// <summary>
    /// Management cache in RAM
    /// </summary>
    class FileCache : ICache
    {
        /// <summary>
        /// Save cache in RAM
        /// </summary>
        private List<CacheObject> m_lstStore = new List<CacheObject>();
        /// <summary>
        /// Cache a object in 10 minitues
        /// </summary>
        private int m_iMinToCache = 10;
        /// <summary>
        /// Lock default constructor
        /// </summary>
        public FileCache() 
        {
            Thread remover = new Thread(new ThreadStart(_RemoveExpridate));
            remover.IsBackground = true;
            remover.Start();
        }
        /// <summary>
        /// Get a cache with keyword
        /// </summary>
        /// <param name="_strKey">Keyword</param>
        /// <returns>A Cache object</returns>
        public object Get(string _strKey)
        {
            CacheObject coTemp = GetCacheObject(_strKey);
            if (coTemp != null)
            {
                LogManager.GetInstance().Info("Get from cache " + _strKey);
                return coTemp.Value;
            }
            return null;
        }
        public CacheObject GetCacheObject(string _strKey)
        {
            return m_lstStore.Where(m => m.Keyword == _strKey).SingleOrDefault();
        }
        public List<CacheObject> GetAllCacheObject()
        {
            return m_lstStore.Where(m=>m.Expridate>DateTime.Now).ToList();
        }
        /// <summary>
        /// Save a cache object with default time to expridate
        /// </summary>
        /// <param name="_strKey">Keyword</param>
        /// <param name="_coInput">Data to cache</param>
        /// <returns></returns>
        public bool Add(string _strKey, object _coInput)
        {
            return this.Add(_strKey, _coInput, m_iMinToCache);
        }
        /// <summary>
        /// Save a cache object with a time to expridate
        /// </summary>
        /// <param name="_strKey">Ketword</param>
        /// <param name="_coInput">Data to cache</param>
        /// <param name="_dtExpDate">Time to expridate</param>
        /// <returns></returns>
        public bool Add(string _strKey, object _coInput, int _iMinuteToCache)
        {
            if (string.IsNullOrEmpty(_strKey))
                throw new Exception("Keyword not null");
            DateTime dtTemp = DateTime.Now.AddMinutes(_iMinuteToCache);
            if (dtTemp <= DateTime.Now)
                throw new Exception("ExpDate < Current time");
            if (this.CheckExist(_strKey))
            {
                throw new Exception("Existing cache object with key: " + _strKey);
            }
            else
            {
                CacheObject coTemp = new CacheObject(_strKey, _coInput, dtTemp);
                m_lstStore.Add(coTemp);
            }
            return this.CheckExist(_strKey);
        }
        /// <summary>
        /// Get all keys
        /// </summary>
        /// <returns>List of keywords</returns>
        public List<string> GetKeys()
        {
            return m_lstStore.Where(m => m.Expridate > DateTime.Now)
                .Select(m => m.Keyword).ToList();
        }
        /// <summary>
        /// Delete a cache object
        /// </summary>
        /// <param name="_strKeyword">Keyword to delete</param>
        /// <returns>Deleted or not</returns>
        public bool Delete(string _strKeyword)
        {
            if (this.CheckExist(_strKeyword))
            {
                CacheObject coTemp = this.GetCacheObject(_strKeyword);
                coTemp.Keyword = null;
                coTemp.Value = null;
                coTemp.Views = 0;
                LogManager.GetInstance().Info("Deleted cache:" + _strKeyword);
                return m_lstStore.Remove(coTemp);
            }
            return false;
        }
        public bool Delete(List<string> _lstKeyword)
        {
            foreach (var item in _lstKeyword)
            {
                Delete(item);
            }
            return true;
        }
        /// <summary>
        /// Delete all cache objects
        /// </summary>
        /// <returns>Deleted or not</returns>
        public bool DeleteAll()
        {
            m_lstStore = new List<CacheObject>();
            return true;
        }
        /// <summary>
        /// Checking existing cache object
        /// </summary>
        /// <param name="_strKey">Keyword</param>
        /// <returns>Existed or not</returns>
        public bool CheckExist(string _strKey)
        {
            return m_lstStore.Exists(m => m.Keyword == _strKey);
        }

        public void _RemoveExpridate()
        {
            //Thread.Sleep(1000 * 60 * 10);
            var query = m_lstStore.Where(m => m.Expridate <= DateTime.Now);
            if (query != null)
            {
                List<string> lstKeyExpri = query.Select(m => m.Keyword).ToList();
                if (lstKeyExpri != null && lstKeyExpri.Count > 0)
                {
                    foreach (var item in lstKeyExpri)
                    {
                        this.Delete(item);
                    }
                }
            }
        }
    }
}
